package cn.ecnu.paper.service.impl;


import cn.ecnu.common.Constant;
import cn.ecnu.common.RedisConstant;
import cn.ecnu.exception.RRXException;
import cn.ecnu.paper.mapper.FieldMapper;
import cn.ecnu.paper.pojo.Field;
import cn.ecnu.paper.service.FieldService;
import cn.ecnu.paper.vo.FieldFrontVo;
import cn.ecnu.paper.vo.FieldTree;
import cn.ecnu.paper.vo.FieldUpdateVo;
import cn.ecnu.paper.vo.ViewFieldVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FieldServiceImpl implements FieldService {

    @Resource
    private FieldMapper fieldMapper;

    private Map<Integer, List<FieldTree>>  id2Children;

    @Autowired
    RedisTemplate<Object, Object> redisTemplate;

    @Override
    public ViewFieldVo getFieldList() {
        // 缓存操作
        ValueOperations<Object, Object> opsForValue = redisTemplate.opsForValue();
        if (BooleanUtils.isTrue(redisTemplate.hasKey(RedisConstant.PAPER_FIELD_CACHE))) {
            log.info(RedisConstant.PAPER_FIELD_CACHE + " 缓存命中");
            return (ViewFieldVo) opsForValue.get(RedisConstant.PAPER_FIELD_CACHE);
        }
        List<FieldTree> fields = fieldMapper.getRootField();
        if (fields == null) return null; // 首先获取所有的根节点

        id2Children = new HashMap<>(); // 组装一个id的所有子id
        List<FieldTree> allFields = fieldMapper.getFieldsList(); // 获取所有的fields, 非root
        for (FieldTree f : allFields) {
            Integer pid = f.getParentId(); // 获取这个field的父亲
            if (!id2Children.containsKey(pid)) {
                id2Children.put(pid, new ArrayList<>());
            }
            id2Children.get(pid).add(f); // 将它加入到父亲阵营中
        }

        fields = fields.stream().peek(this::recursiveNode).collect(Collectors.toList()); // 递归遍历所有的field, 为他们添加子节点
        ViewFieldVo vo = new ViewFieldVo();
        vo.setFields(fields);
        opsForValue.setIfAbsent(RedisConstant.PAPER_FIELD_CACHE, vo, 30, TimeUnit.MINUTES);
        return vo;
    }

    // 采用递归方式的一个问题就是速度比较慢, 而且需要多次访问数据库
    private void recursiveNode(FieldTree fieldTree) {
        // 获得当前节点的所有子节点
        if (fieldTree == null) return;
        List<FieldTree> fields = id2Children.getOrDefault(fieldTree.getFieldId(), null); // 获取当前节点的子节点
        // 遍历所有的子节点, 为它们添加自己的子节点
        if (fields == null) return; // 如果子节点为空, 停止迭代
        List<FieldTree> children = fields.stream().peek(this::recursiveNode).collect(Collectors.toList());
        // 设置当前节点的子节点
        fieldTree.setChildren(children);
    }


    @Override
    public Field insertField(FieldFrontVo vo) {
        Field field = new Field();
        field.setParentId(vo.getParentId());
        field.setFieldName(vo.getFieldName());
        fieldMapper.insertField(field);
        return field;
    }

    @Override
    public int deleteById(Integer fieldId) {
        int count = fieldMapper.countChild(fieldId);
        if (count > 0) throw new RRXException(Constant.DELETE_ERROR.getMsg(), Constant.DELETE_ERROR.getCode());
        return fieldMapper.deleteById(fieldId);
    }

    @Override
    public int updateField(Field vo) {
        if (vo.getFieldId() == null) throw new RRXException(Constant.ARGUMENT_INVALID.getMsg(), Constant.ARGUMENT_INVALID.getCode());
        Field field = fieldMapper.getFieldById(vo.getFieldId());
        if (field == null) throw new RRXException(Constant.NO_RESOURCE.getMsg(), Constant.NO_RESOURCE.getCode());
        return fieldMapper.updateField(vo);
    }
}
